import axios from 'axios'
import qs from 'qs'
import { TOKEN_KEY } from '@/utils/constant'
import Storage from '@/utils/Storage'
import { ResultEnum } from '@/enums/ResultEnum'
import { useUserStore } from '@/store'
import { readAsText } from '@/utils'
import type { AxiosRequestConfig } from 'axios'

const service = axios.create({
  baseURL: import.meta.env.VITE_APP_BASE_API,
  timeout: 50000,
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  // 'Content-Type': 'application/x-www-form-urlencoded',
  // 'Content-Type': 'application/json;charset=UTF-8'
  paramsSerializer: params => {
    return qs.stringify(params)
  }
})

// 请求拦截器
service.interceptors.request.use(
  config => {
    const accessToken = Storage.getStorage(TOKEN_KEY)
    if (accessToken) {
      config.headers.Authorization = `Bearer ${accessToken}`
    }
    return config
  },
  (error: any) => {
    return Promise.reject(error)
  }
)

const sessionExpired = () => {
  ElNotification({
    title: '提示',
    message: '您的会话已过期，请重新登录',
    type: 'info'
  })
  useUserStore()
    .clearUserSession()
    .then(() => {
      location.reload() // 为了重新实例化vue-router对象 避免bug
    })
}

service.interceptors.response.use(
  response => {
    // 检查配置的响应类型是否为二进制类型（'blob' 或 'arraybuffer'）, 如果是，直接返回响应对象
    if (response.config.responseType === 'blob' || response.config.responseType === 'arraybuffer') {
      return response
    }

    const { code, message } = response.data
    if (code === ResultEnum.SUCCESS) {
      return response.data
    }
    if (code === ResultEnum.TOKEN_INVALID) {
      sessionExpired()
      return Promise.reject('会话过期')
    }

    ElMessage.error(message || '系统出错')
    return Promise.reject(message || 'Error')
  },
  (error: any) => {
    ElMessage.error('系统出错')
    return Promise.reject(error.message || 'Error')
  }
)

export default service

export function get<T = any>(url: string, data?: any) {
  return new Promise<ResponseData<T>>((resolve, reject) => {
    service({
      url,
      method: 'get',
      params: data
    })
      .then(res => {
        resolve(res as any)
      })
      .catch(err => {
        reject(err)
      })
  })
}

export function post<T = any>(url: string, data?: any) {
  return new Promise<ResponseData<T>>((resolve, reject) => {
    service({
      url,
      method: 'post',
      data
    })
      .then(res => {
        resolve(res as any)
      })
      .catch(err => {
        reject(err)
      })
  })
}

export function upload(url: string, data: Record<string, string | File>) {
  const keys = Object.keys(data)
  if (keys.length === 0) {
    ElMessage.error('上传的数据不能为空')
    return
  }
  const formData = new FormData()
  keys.forEach(key => {
    formData.append(key, data[key])
  })

  return new Promise<ResponseData>((resolve, reject) => {
    service({
      url,
      method: 'post',
      data: formData,
      headers: {
        'Content-Type': 'multipart/form-data;charset=UTF-8'
      }
    })
      .then(res => {
        resolve(res as any)
      })
      .catch(() => reject())
  })
}

interface DownloadOptions {
  url: string
  data: any
  method?: 'get' | 'post'
  fileName?: string
  mimeType?: string
}

export function download(options: DownloadOptions) {
  const { url, data, method = 'get', fileName = '', mimeType = 'application/vnd.ms-excel' } = options

  const config: AxiosRequestConfig = {
    url,
    method,
    responseType: 'blob'
  }
  if (method === 'get') {
    config['params'] = data
  } else {
    config['data'] = data
  }
  return new Promise<void>((resolve, reject) => {
    service(config)
      .then(response => {
        readAsText(response.data).then(result => {
          try {
            // 数据如果可以被转化成对象，说明是 {code, message, result} 格式，反之是正常的文件流
            const jsonData = JSON.parse(result as string)
            const { code } = jsonData
            if (code === ResultEnum.TOKEN_INVALID) {
              sessionExpired()
              return reject()
            }
            ElMessage.error('返回的数据不是文件流，请检查')
            reject()
          } catch {
            // 解析成对象失败，说明是正常的文件流
            downLoadBlobFile(response.data, fileName, mimeType)
            resolve()
          }
        })
      })
      .catch(err => {
        reject(err)
      })
  })
}

export function downLoadBlobFile(data: any, name: string, mimeType: string) {
  const blob = new Blob([data], { type: mimeType })
  const fileName = name || 'download'
  const link = document.createElement('a')
  link.href = URL.createObjectURL(blob)
  link.download = fileName

  document.body.appendChild(link)
  link.click()

  document.body.removeChild(link)
  URL.revokeObjectURL(link.href)
}
